home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / technical documentation / develop / develop issue 27 / develop issue 27 code / internet config assistant / iconbutton / iconbutton.c next >
Encoding:
C/C++ Source or Header  |  1996-05-04  |  16.3 KB  |  704 lines

  1. /*
  2.     File:        IconButton.c
  3.  
  4.     Contains:    CDEF implementing Icon Button
  5.  
  6.     Written by:    Arno Gourdol
  7.  
  8.     Copyright:    © 1993-1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13. /*
  14.     How to use...
  15.  
  16.     Create a control with the following ID:
  17.         64: 32x32 icon
  18.         65: 16x16 icon
  19.         66: 12x12 icon
  20.     
  21.     The value of the control is the ID of the icon family to 
  22.     use to display (icl8, icl4, ICON...).
  23. */
  24.  
  25. #include <Controls.h>
  26. #include <Windows.h>
  27. #include <QDOffscreen.h>
  28. #include <LowMem.h>
  29. #include <Icons.h>
  30.  
  31.  
  32. // Variants
  33. enum
  34. {
  35.     kLargeIconVariant = 0x00,        // Use 32x32 icon
  36.     kSmallIconVariant = 0x01,        // Use 16x16 icon
  37.     kMiniIconVariant = 0x02            // Use 12x12 icon
  38. };
  39.  
  40.  
  41. struct DrawControlInfo
  42. {
  43.     Rect controlBounds;        // Rectangle enclosing the button
  44.     Boolean    hilited;        // True if button is pushed
  45.     Boolean active;            // True if button is not dimmed
  46.     SInt16 iconFamilyID;    // Icon family ID or -1
  47.     UInt16 variant;
  48. };
  49. typedef struct DrawControlInfo  DrawControlInfo;
  50.  
  51. struct PortState
  52. {
  53.     // Port we switched from
  54.     GrafPtr        savedPort;        
  55.     
  56.     // Saved state of the WMgrCPort
  57.     RgnHandle savedClip;        
  58.     Point savedOrigin;
  59.     RGBColor savedFgColor;
  60.     RGBColor savedBgColor;
  61.     PenState savedPen;
  62.     SInt16 savedPenVis;
  63.     SInt16 savedTxMode;
  64.     
  65. };
  66. typedef struct PortState PortState;
  67.  
  68.  
  69. pascal long main(UInt16 variant, ControlHandle theControl, SInt16 message, UInt32 param);
  70.  
  71. Boolean UseGrayUI(UInt16 depth, UInt16 deviceFlags);
  72. void SetForeGray(UInt16 value);
  73. UInt16 GetIconSize(UInt16 variant);
  74. Boolean GetIconRect(const Rect& controlBounds, UInt16 variant, Rect* iconRect);
  75.  
  76. void DoDrawControl(ControlHandle theControl, UInt16 variant);
  77. long DoTestControl(ControlHandle theControl, Point hit);
  78. void DoCalcRegion(ControlHandle theControl, RgnHandle controlRegion);
  79.  
  80. void SetWindowManagerPort(PortState *state);
  81. void RestoreSavedPort(PortState *state);
  82. Boolean    AreWeOffscreen(void);
  83.  
  84.  
  85. // WARNING: Some compilers require the main entry point to be
  86. // the first routine in the source file.
  87. pascal long main(UInt16 variant, ControlHandle theControl, SInt16 message, UInt32 param)
  88. {
  89.     long result = 0;
  90.  
  91.     if (message > 2)    
  92.         message -= 7;
  93.         
  94.     switch (message)
  95.     {
  96.         // Handle draw message
  97.         case drawCntl: 
  98.             DoDrawControl(theControl, variant);
  99.             break;
  100.             
  101.         // Handle hit-test message    
  102.         case testCntl: 
  103.             result = DoTestControl(theControl, *(Point *)¶m);
  104.             break;
  105.             
  106.         // Handle 24-bit mode calc regions call
  107.         case calcCRgns:
  108.             // 24-bit dirty version
  109.             param &= 0x00FFFFFF;        // Clear the high byte
  110.             DoCalcRegion(theControl, (RgnHandle)param);
  111.             param &= 0x7FFFFFFF;        // Clear high bit
  112.             break;
  113.             
  114.         case calcCntlRgn-7:
  115.         case calcThumbRgn-7:
  116.             // 32-bit clean
  117.             DoCalcRegion(theControl, (RgnHandle)param);
  118.             break;
  119.     }
  120.  
  121.     return result;
  122. }
  123.  
  124.  
  125.  
  126. // --------------------------------------------------------------------
  127. //    AreWeOffscreen
  128. // --------------------------------------------------------------------
  129. //
  130. //    Compares base address of the current port to screen base to 
  131. //    determine if we're drawing on or offscreen.
  132. //
  133.  
  134. Boolean AreWeOffscreen(void)
  135. {
  136.     GrafPtr savedPort;
  137.     Ptr baseAddr;    
  138.     
  139.     GetPort(&savedPort);
  140.     
  141.     // If we're color, then we get base address
  142.     // from pixmap....
  143.     if (((CGrafPtr)savedPort)->portVersion & 0xC000)
  144.         baseAddr = (**((CGrafPtr)savedPort)->portPixMap).baseAddr;
  145.     else
  146.         baseAddr = savedPort->portBits.baseAddr;
  147.     
  148.     return baseAddr != LMGetScrnBase();    
  149. }
  150.  
  151.  
  152.  
  153. // --------------------------------------------------------------------
  154. //    UseGrayUI
  155. // --------------------------------------------------------------------
  156. //
  157. //    Returns true if color environment is sufficient to use shades of 
  158. //  grey.
  159. //
  160.  
  161. Boolean UseGrayUI(UInt16 depth, UInt16 deviceFlags)
  162. {
  163.     // If bith depth is 256 colors or more,
  164.     // or if 4 bit depth gray scale the use gray UI
  165.     return (depth >= 8) || ((depth == 4) && !(deviceFlags & (1L << gdDevType)));
  166. }
  167.  
  168.  
  169.  
  170. // --------------------------------------------------------------------
  171. //    SetForeGray
  172. // --------------------------------------------------------------------
  173. //
  174. //    Set the fore color to a shade of grey.
  175. //
  176.  
  177. void SetForeGray(UInt16 value)
  178. {
  179.     RGBColor color;
  180.  
  181.     color.red = value;
  182.     color.green = value;
  183.     color.blue = value;
  184.     
  185.     RGBForeColor(&color);
  186. }
  187.  
  188.  
  189.  
  190. // --------------------------------------------------------------------
  191. //    GetIconSize
  192. // --------------------------------------------------------------------
  193. //
  194. //    Returns the icon size in pixel, based on the variant.
  195. //
  196.  
  197. UInt16 GetIconSize(UInt16 variant)
  198. {
  199.     short result;
  200.     
  201.     switch(variant & 0x03)
  202.     {
  203.         case kSmallIconVariant:
  204.             result = 16;
  205.             break;
  206.             
  207.         case kMiniIconVariant:
  208.             result = 12;
  209.             break;
  210.             
  211.         default:
  212.             result = 32;    // 0 or other, 32 pixel wide icon
  213.     }
  214.     return result;
  215. }
  216.  
  217.  
  218.  
  219. // --------------------------------------------------------------------
  220. //    GetIconRect
  221. // --------------------------------------------------------------------
  222. //
  223. //    Returns the rect in which to display the icon based on the variant 
  224. //    and control rect.
  225. //    Returns true if the icon rectangle is not empty
  226. //
  227.  
  228. Boolean GetIconRect(const Rect& controlBounds, UInt16 variant, Rect* iconRect)
  229. {
  230.     Boolean result;
  231.     
  232.     UInt16 iconSize = GetIconSize(variant);
  233.  
  234.     UInt16 controlWidth = controlBounds.right - controlBounds.left;
  235.     UInt16 controlHeight = controlBounds.bottom - controlBounds.top;
  236.     
  237.     
  238.     if (controlWidth < iconSize || controlHeight < iconSize)
  239.     {
  240.         // The control is too small to display the icon
  241.         // Return an empty rectangle
  242.         iconRect->top = 0;
  243.         iconRect->left = 0;
  244.         iconRect->right = 0;
  245.         iconRect->bottom = 0;
  246.  
  247.         result = false;
  248.     }
  249.     else
  250.     {
  251.         SInt16 temp;
  252.         *iconRect = controlBounds;
  253.  
  254.         // Center the iconRect inside the controlRect, pinning it if necessary
  255.         temp = iconRect->top + ((controlHeight - iconSize + 1) >> 1);
  256.         if (temp > iconRect->top)
  257.             iconRect->top = temp;
  258.             
  259.         temp = iconRect->left + ((controlWidth - iconSize + 1) >> 1);
  260.         if (temp > iconRect->left)
  261.             iconRect->left = temp;
  262.         
  263.         temp = iconRect->top + iconSize;
  264.         if (temp < iconRect->bottom)
  265.             iconRect->bottom = temp;
  266.             
  267.         temp = iconRect->left + iconSize;
  268.         if (temp < iconRect->right)
  269.             iconRect->right = temp;
  270.  
  271.         result = true;
  272.     }
  273.     return result;
  274. }
  275.  
  276.  
  277.  
  278. // --------------------------------------------------------------------
  279. //    DrawControlProc
  280. // --------------------------------------------------------------------
  281. //
  282. //    Callback for device loop to draw the control.
  283. //
  284.  
  285. static pascal void DrawControlProc(UInt16 depth, UInt16 deviceFlags, 
  286.                         GDHandle targetDevice, DrawControlInfo* info)
  287. {
  288. #pragma unused (targetDevice)
  289.  
  290.     if (!UseGrayUI(depth, deviceFlags))
  291.     {
  292.         // Draw in black and white
  293.         Rect frameRect = info->controlBounds;
  294.  
  295.         if(info->hilited)
  296.             PaintRect(&frameRect);
  297.         else
  298.             EraseRect(&frameRect);
  299.  
  300.         FrameRect(&frameRect);
  301.     }
  302.     else
  303.     {
  304.         // Draw using shades of grey
  305.         UInt16 fillGray;
  306.  
  307.         UInt16 frameHiliteGray;
  308.         UInt16 frameShadowGray;
  309.  
  310.         UInt16 hiliteGray;
  311.         UInt16 shadowGray;
  312.         UInt16 cornerGray;
  313.         
  314.         UInt16 topLeftCornerGray;
  315.         UInt16 botRightCornerGray;
  316.         UInt16 hilite2Gray;
  317.         UInt16 shadow2Gray;
  318.  
  319.         Rect frameRect = info->controlBounds;
  320.         
  321.         //
  322.         // Save the background and foreground colors
  323.         //
  324.         RGBColor oldForeColor;
  325.         RGBColor oldBackColor;
  326.  
  327.         GetForeColor(&oldForeColor);
  328.         GetBackColor(&oldBackColor);
  329.         
  330.         // What is the smallest side of the frame
  331.         // If one of the side is larger than 20, it's a big button
  332.         Boolean isBigButton = (frameRect.right - frameRect.left > 20) || 
  333.                 (frameRect.bottom - frameRect.top > 20);
  334.         
  335.         //
  336.         // Determine the colors
  337.         //
  338.         
  339.         if (!info->active)
  340.         {
  341.             // Dimmed button
  342.             frameHiliteGray = 0x7777;
  343.             frameShadowGray = 0x7777;
  344.             fillGray  = 0xDDDD;
  345.             hiliteGray = 0xEEEE;
  346.             cornerGray = 0xCCCC;
  347.             shadowGray = 0xAAAA;
  348.         }
  349.         else if (info->hilited)
  350.         {
  351.             // Selected (pushed) button
  352.             frameHiliteGray = 0x2222;
  353.             frameShadowGray = 0x6666;
  354.             fillGray  = 0x8888;
  355.             hiliteGray = 0x5555;
  356.             cornerGray = 0x7777;
  357.  
  358.             if(isBigButton)
  359.             {
  360.                 shadowGray = 0x4444;
  361.                 shadow2Gray = 0x5555;
  362.                 hilite2Gray = 0x7777;
  363.                 topLeftCornerGray = 0x8888;
  364.                 botRightCornerGray = 0x2222;
  365.             }
  366.             else
  367.             {
  368.                 shadowGray = 0xAAAA;
  369.             }
  370.         }
  371.         else
  372.         {
  373.             // Normal button
  374.             frameHiliteGray = 0x6666;
  375.             frameShadowGray = 0x3333;
  376.             fillGray = 0xCCCC;
  377.             shadowGray = 0x9999;
  378.             cornerGray = 0xCCCC;
  379.  
  380.             if(isBigButton)
  381.             {
  382.                 botRightCornerGray = 0x8888;
  383.                 hiliteGray = 0x2222;
  384.                 hilite2Gray = 0xFFFF;
  385.                 shadow2Gray = 0x5555;
  386.                 topLeftCornerGray = 0xFFFF;
  387.             }
  388.             else
  389.                 hiliteGray = 0xFFFF;
  390.         }
  391.  
  392.  
  393.         //
  394.         // Draw the button
  395.         //
  396.         {
  397.             --frameRect.right;
  398.             --frameRect.bottom;
  399.             frameRect.left++;
  400.             frameRect.top++;
  401.  
  402.             // Draw the inside of the rect
  403.             SetForeGray(fillGray);
  404.             PaintRect(&frameRect);
  405.             
  406.             // Draw the inside top left hilite thingie
  407.             SetForeGray(hiliteGray);
  408.             MoveTo(frameRect.left, frameRect.bottom - 1);
  409.             LineTo(frameRect.left, frameRect.top);                    // Left side
  410.             LineTo(frameRect.right - 1, frameRect.top);                // Top side
  411.             
  412.             
  413.             // Draw the inside bottom right shadow thingie
  414.             SetForeGray(shadowGray);
  415.             MoveTo(frameRect.right - 1, frameRect.top);
  416.             LineTo(frameRect.right - 1, frameRect.bottom - 1);        // Right side
  417.             LineTo(frameRect.left + 1, frameRect.bottom - 1);        // Bottom side
  418.             
  419.             if (isBigButton)
  420.             {
  421.                 // Draw the more inside top left hilite thingie
  422.                 InsetRect(&frameRect, 1 , 1);
  423.                 MoveTo(frameRect.left, frameRect.bottom - 1);
  424.                 SetForeGray(hilite2Gray);
  425.                 LineTo(frameRect.left, frameRect.top );                // Left inside side
  426.                 LineTo(frameRect.right - 1, frameRect.top);            // Top inside side
  427.  
  428.                 // Draw the more inside bottom right shadow thingie
  429.                 SetForeGray(shadow2Gray);
  430.                 LineTo(frameRect.right - 1, frameRect.bottom - 1);    // Right inside
  431.                 LineTo(frameRect.left + 1, frameRect.bottom - 1);     // Bottom inside
  432.                 InsetRect(&frameRect, -1, -1);
  433.             }
  434.  
  435.             // Draw the corners
  436.             if (isBigButton)
  437.             {
  438.                 SetForeGray(cornerGray);
  439.                 MoveTo(frameRect.right -1, frameRect.top);
  440.                 Line(-1, 1);
  441.                 MoveTo(frameRect.left, frameRect.bottom -1);
  442.                 Line(1, -1);
  443.                 
  444.                 SetForeGray(topLeftCornerGray);
  445.                 MoveTo(frameRect.left, frameRect.top);
  446.                 Line(0,0);
  447.  
  448.                 SetForeGray(botRightCornerGray);
  449.                 MoveTo(frameRect.right -1, frameRect.bottom -1);
  450.                 Line(0,0);
  451.                 
  452.                 SetForeGray(shadowGray);
  453.                 MoveTo(frameRect.right - 2, frameRect.bottom - 2);
  454.                 Line(0,0);
  455.  
  456.                 if(info->hilited)
  457.                 {
  458.                     SetForeGray(hiliteGray);
  459.                     MoveTo(frameRect.left + 1, frameRect.top + 1);
  460.                     Line(0,0);
  461.                 }
  462.             }
  463.             else
  464.             {
  465.                 SetForeGray(cornerGray);
  466.                 MoveTo(frameRect.right -1, frameRect.top);
  467.                 Line(0,0);
  468.                 MoveTo(frameRect.left, frameRect.bottom -1);
  469.                 Line(0, 0);
  470.             }
  471.  
  472.             --frameRect.left;
  473.             --frameRect.top;
  474.  
  475.             {
  476.                 // Draw the frame
  477.                 SetForeGray(frameHiliteGray);
  478.                 MoveTo(frameRect.left, frameRect.bottom);
  479.                 LineTo(frameRect.left, frameRect.top);        // Left side
  480.                 LineTo(frameRect.right, frameRect.top);        // Top side
  481.                 
  482.                 
  483.                 // Draw the inside bottom right shadow thingie
  484.                 SetForeGray(frameShadowGray);
  485.                 MoveTo(frameRect.right, frameRect.top);
  486.                 LineTo(frameRect.right, frameRect.bottom);    // Right side
  487.                 LineTo(frameRect.left, frameRect.bottom);    // Bottom side
  488.             }
  489.         }
  490.         //
  491.         // Restore color environment
  492.         //
  493.         RGBForeColor(&oldForeColor);
  494.         RGBBackColor(&oldBackColor);
  495.     }
  496.  
  497.  
  498.     //
  499.     // Draw the icon
  500.     //
  501.     if (info->iconFamilyID != -1)
  502.     {
  503.         Rect iconRect;
  504.                 
  505.         if (GetIconRect(info->controlBounds, info->variant, &iconRect))
  506.         {
  507.             // Set back to B&W before drawing icons
  508.             ForeColor(blackColor);
  509.             BackColor(whiteColor);
  510.             
  511.             {
  512.                 IconTransformType iconTransform = kTransformNone;
  513.                 
  514.                 if (!info->active)
  515.                     iconTransform = kTransformDisabled;
  516.                 else if (info->hilited)
  517.                     iconTransform = kTransformSelected;
  518.  
  519.                 PlotIconID(&iconRect, kAlignAbsoluteCenter, 
  520.                                 iconTransform, info->iconFamilyID);
  521.             }
  522.         }
  523.     }
  524.  
  525. }
  526.  
  527.  
  528.  
  529. // --------------------------------------------------------------------
  530. //    DoDrawControl
  531. // --------------------------------------------------------------------
  532. //
  533. //    CDEF entry point responsible for drawing the control.
  534. //
  535.  
  536. void DoDrawControl(ControlHandle theControl, UInt16 variant)
  537. {
  538.     DrawControlInfo drawControlInfo;
  539.     Rect contrlRect;
  540.     short hilite;
  541.     GrafPtr    savedPort;
  542.     #define kFakeDeviceFlags 0xA801
  543.  
  544.     // Draw iff both the control and its parent window are visible
  545.     if (!(**theControl).contrlVis || !((WindowPeek)((**theControl).contrlOwner))->visible )
  546.         return;            // Control is not visible. Don't draw anything
  547.     
  548.     contrlRect = (**theControl).contrlRect;
  549.     hilite = (**theControl).contrlHilite;
  550.     drawControlInfo.controlBounds = contrlRect;
  551.     drawControlInfo.iconFamilyID = GetControlValue(theControl);
  552.     drawControlInfo.variant = variant;
  553.     drawControlInfo.hilited = (hilite > 0) && (hilite < 254);
  554.     drawControlInfo.active = (hilite != 255);
  555.     
  556.     GetPort(&savedPort);
  557.     
  558.     // Use deviceloop iff we're on a color qd machine, if we're not offscreen
  559.     // and if we're not in the middle of a picture definition
  560.     if ((LMGetROM85()<=0x3FFF) && !AreWeOffscreen() && !(savedPort->picSave) )
  561.     {    
  562.         PortState portState;
  563.         SetWindowManagerPort(&portState);
  564.         {
  565.             RgnHandle contrlRgn = NewRgn();
  566.             RectRgn(contrlRgn, &contrlRect);
  567.             DeviceLoop(contrlRgn, (DeviceLoopDrawingProcPtr)DrawControlProc, 
  568.                         (UInt32)&drawControlInfo, (DeviceLoopFlags)0);
  569.             DisposeRgn(contrlRgn);
  570.         }
  571.         RestoreSavedPort(&portState);
  572.     }
  573.     else
  574.     {
  575.         GWorldPtr curWorld;
  576.         GDHandle curGD;
  577.         
  578.         // Get current gworld so we can pass its device's depth to 
  579.         // our drawing proc
  580.         GetGWorld(&curWorld, &curGD);
  581.         DrawControlProc((**(**curGD).gdPMap).pixelSize, 
  582.                             kFakeDeviceFlags, NULL, &drawControlInfo);    
  583.     }    
  584. }
  585.  
  586.  
  587.  
  588. // --------------------------------------------------------------------
  589. //    DoTestControl
  590. // --------------------------------------------------------------------
  591. //
  592. //    CDEF entry point responsible for hit-testing the control.
  593. //
  594.  
  595. long DoTestControl(ControlHandle theControl, Point hit)
  596. {
  597.     if((**theControl).contrlHilite == 255)
  598.     {
  599.         return 0;            // If dimmed, nothing can be hit
  600.     }
  601.     else
  602.     {
  603.         Rect hitRect = (**theControl).contrlRect;
  604.         if (PtInRect(hit, &hitRect))
  605.             return inButton;
  606.         else
  607.             return 0;
  608.     }
  609.  
  610. }
  611.  
  612.  
  613.  
  614. // --------------------------------------------------------------------
  615. //    DoCalcRegion
  616. // --------------------------------------------------------------------
  617. //
  618. //    CDEF entry point responsible for calculating the regions of
  619. //    the control.
  620. //
  621.  
  622. void DoCalcRegion(ControlHandle theControl, RgnHandle controlRegion)
  623. {
  624.     Rect contrlRect = (**theControl).contrlRect;
  625.     RectRgn(controlRegion, &contrlRect);
  626. }
  627.  
  628.  
  629.  
  630. // --------------------------------------------------------------------
  631. //    SetWindowManagerPort
  632. // --------------------------------------------------------------------
  633. //
  634. //    Set the drawing environment to be the Window Manager.
  635. //    Used if color is available, but the grafport in which the control 
  636. //    is draw is B&W.
  637. //
  638.  
  639. void SetWindowManagerPort(PortState *state)
  640. {
  641.     GrafPtr windowManagerPort;    //    WMgrCPort
  642.     Point origin;
  643.     
  644.     GetPort(&(state->savedPort));
  645.     
  646.     // Convert origin of current port to global coordinates
  647.     // so that when we switch to the window manager's port, we can
  648.     // set up the coordinate system correctly
  649.     origin.h = 0;
  650.     origin.v = 0;
  651.     LocalToGlobal(&origin);
  652.         
  653.     // switch to the wmgrcport
  654.     GetCWMgrPort((CGrafPtr*)&windowManagerPort);
  655.     SetPort(windowManagerPort);
  656.     
  657.     // remember the colors of the wmgrcport
  658.     GetForeColor(&(state->savedFgColor));
  659.     GetBackColor(&(state->savedBgColor));        
  660.         
  661.     // remember old origin of wmgrcport
  662.     state->savedOrigin.h = windowManagerPort->portRect.left;
  663.     state->savedOrigin.v = windowManagerPort->portRect.top;
  664.     
  665.     // synchronize wmgrcport's coordinate system with that of the saved port
  666.     SetOrigin(-origin.h, -origin.v);        
  667.     
  668.     // remember clip of window manager port and set clip to visRgn of savePort
  669.     state->savedClip = NewRgn();
  670.     GetClip(state->savedClip);
  671.     SetClip(state->savedPort->visRgn);
  672.     
  673.     GetPenState(&(state->savedPen));
  674.     state->savedTxMode = windowManagerPort->txMode;
  675.     
  676.     state->savedPenVis = windowManagerPort->pnVis;
  677.     // maintain pnVis from savePort        
  678.     windowManagerPort->pnVis = state->savedPort->pnVis;        
  679. }
  680.  
  681.  
  682.  
  683. // --------------------------------------------------------------------
  684. //    RestoreSavedPort
  685. // --------------------------------------------------------------------
  686. //
  687. //    Restore the drawing context.
  688. //
  689.  
  690. void RestoreSavedPort(PortState* state)
  691. {
  692.     SetOrigin(state->savedOrigin.h, state->savedOrigin.v);
  693.     SetClip(state->savedClip);
  694.     DisposeRgn(state->savedClip);
  695.     SetPenState(&(state->savedPen));
  696.     RGBForeColor(&(state->savedFgColor));
  697.     RGBBackColor(&(state->savedBgColor));
  698.     TextMode(state->savedTxMode);
  699.     SetPort(state->savedPort);    
  700. }
  701.     
  702.     
  703.     
  704.